package com.shiroha.chat.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.shiroha.chat.pojo.dto.ChatMessage;
import com.shiroha.chat.service.IChatService;
import com.shiroha.common.event.ServiceEvent;
import com.shiroha.common.exception.BadRequestException;
import com.shiroha.common.feign.client.UserClient;
import com.shiroha.common.utils.JsonUtils;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 聊天消息 WS 处理器
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ChatMessageWebSocketHandler extends AbstractWebSocketHandler {

    private final IChatService chatService;
    private final UserClient userClient;
    private final Map<UUID, WebSocketSession> userSessions = new ConcurrentHashMap<>();

    @EventListener(ServiceEvent.class)
    public void onEvent(final ServiceEvent event) {
        try {
            ChatMessage chatMessage = event.getDataAsType(ChatMessage.class);
            MessageHandler messageHandler = MessageHandlerFactory.getMessageHandler(chatMessage.getType());
            messageHandler.handleMessage(chatMessage);
            sendMessage(chatMessage);
        } catch (JsonProcessingException e) {
            log.error("消息反序列化失败", e);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void afterConnectionEstablished(@NonNull WebSocketSession session) {
        UUID userId = extractUserId(session);
        userSessions.put(userId, session);
        log.info("User {} connected", userId);
    }

    @Override
    protected void handleTextMessage(@NonNull WebSocketSession session, @NonNull TextMessage message) throws Exception {
        ChatMessage chatMessage = JsonUtils.deserialize(message.getPayload(), ChatMessage.class);
        try {
            sendMessage(chatMessage);
        } catch (BadRequestException e) {

        }
    }

    @Override
    public void afterConnectionClosed(@NonNull WebSocketSession session, @NonNull CloseStatus status) {
        UUID userId = extractUserId(session);
        userSessions.remove(userId);
        log.info("用户断开连接{}", userId);
    }

    // 从session中提取用户ID
    private UUID extractUserId(WebSocketSession session) {
        return UUID.fromString(session.getPrincipal().getName());
    }

    // 发送消息给接收者
    private void sendMessage(ChatMessage chatMessage) throws Exception {
        TextMessage textMessage = new TextMessage(JsonUtils.serialize(chatMessage));

        // 开始发送消息
        log.info("发送者{}开始发送消息，消息类型{}", chatMessage.getSenderId(), chatMessage.getType().getDescription());
        Optional.ofNullable(chatMessage.getReceiverId())
                .ifPresentOrElse(receiverId -> sendMessageToUser(receiverId, textMessage),
                        () -> {
                            Long groupId = chatMessage.getGroupId();
                            if(groupId == null) throw new BadRequestException("群组ID不能为空");
                            sendMessageToGroupMembers(groupId, textMessage);
                        });

        // 消息发送成功后对消息进行保存
    }

    // 私发消息逻辑
    private void sendMessageToUser(@NonNull UUID receiverId, @NonNull TextMessage textMessage) {
        WebSocketSession receiverSession = userSessions.get(receiverId);
        if (receiverSession != null && receiverSession.isOpen()) {
            try {
                receiverSession.sendMessage(textMessage);
            } catch (Exception e) {
                log.error("私发消息失败，接收者{}", receiverId, e);
            }
        }
    }

    // 群发消息逻辑
    private void sendMessageToGroupMembers(@NonNull Long groupId, @NonNull TextMessage textMessage) {
        // 获取群内所有成员的用户ID
        UUID[] memberIds = userClient.getMemberIdsByGroupId(groupId).getData();
        // 创建一个 List 来保存所有的 CompletableFuture
        List<CompletableFuture<Void>> futures = new ArrayList<>();

        for (UUID memberId : memberIds) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                WebSocketSession memberSession = userSessions.get(memberId);
                if (memberSession != null && memberSession.isOpen()) {
                    try {
                        memberSession.sendMessage(textMessage);
                    } catch (Exception e) {
                        log.error("群发消息失败，群组{} 成员{}", groupId, memberId, e);
                    }
                }
            });
            futures.add(future);
        }

        // 等待所有的 CompletableFuture 完成
        CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        allOf.join(); // 阻塞主线程，直到所有消息发送完成
    }

    private void saveChatMessage(ChatMessage chatMessage) {
        chatService.saveChatMessage(chatMessage);
    }
}
